=begin pod :kind("Type") :subkind("class") :category("domain-specific")

=TITLE class IO::Spec::Win32

=SUBTITLE Platform specific operations on file and directory paths for Windows

    class IO::Spec::Win32 is IO::Spec::Unix { }

An object of this type is available via the variable C<$*SPEC> if the
Raku interpreter is running on a Windows-like platform.

About this class and its related classes also see
L<IO::Spec|/type/IO::Spec>.

=head1 Methods

=head2 method basename

Defined as:

    method basename(Str:D $path --> Str:D)

Takes a path as a string and returns a possibly-empty portion after the
last slash or backslash:

    IO::Spec::Win32.basename("foo/bar/") .raku.say; # OUTPUT: «""␤»
    IO::Spec::Win32.basename("foo/bar\\").raku.say; # OUTPUT: «""␤»
    IO::Spec::Win32.basename("foo/bar/.").raku.say; # OUTPUT: «"."␤»
    IO::Spec::Win32.basename("foo/bar")  .raku.say; # OUTPUT: «"bar"␤»

=head2 method canonpath

Defined as:

    method canonpath(Str() $path, :$parent --> Str:D)

Returns a string that is a canonical representation of C<$path>. If C<:$parent>
is set to true, will also clean up references to parent directories. B<NOTE:>
the routine does not access the filesystem.

    IO::Spec::Win32.canonpath("C:/foo//../bar/../ber").say;
    # OUTPUT: «C:\foo\..\bar\..\ber␤»

    IO::Spec::Win32.canonpath("C:/foo///./../bar/../ber").say;
    # OUTPUT: «C:\foo\..\bar\..\ber␤»

    IO::Spec::Win32.canonpath("C:/foo///./../bar/../ber", :parent).say;
    # OUTPUT: «C:\ber␤»

=head2 method catdir

Defined as:

    method catdir (*@parts --> Str:D)

Concatenates multiple path fragments and returns the canonical
representation of the resultant path as a string. The C<@parts> are
L«C<Str>|/type/Str» objects and are allowed to contain path separators.

    IO::Spec::Win32.catdir(<foo/bar ber raku>).say;
    # OUTPUT: «foo\bar\ber\raku␤»

=head2 method catfile

Alias for L«C<catdir>|/routine/catdir».

=head2 method catpath

Defined as:

    method catpath (Str:D $volume, Str:D $dir, Str:D $file --> Str:D)

Concatenates a path from given volume, a chain of directories, and file.
An empty string can be given for any of the three arguments. No attempt
to make the path canonical is made. Use
L«C<canonpath>|/routine/canonpath» for that purpose.

    IO::Spec::Win32.catpath('C:', '/some/dir', 'foo.txt').say;
    # OUTPUT: «C:/some/dir\foo.txt␤»

    IO::Spec::Win32.catpath('C:', '/some/dir', '').say;
    # OUTPUT: «C:/some/dir␤»

    IO::Spec::Win32.catpath('', '/some/dir', 'foo.txt').say;
    # OUTPUT: «/some/dir\foo.txt␤»

    IO::Spec::Win32.catpath('E:', '', 'foo.txt').say;
    # OUTPUT: «E:foo.txt␤»

=head2 method devnull

Defined as:

    method devnull(--> Str:D)

Returns the string C<"nul"> representing the
L<"Null device"|https://en.wikipedia.org/wiki/Null_device>:

=for code
$*SPEC.devnull.IO.spurt: "foo bar baz";

=head2 method dir-sep

Defined as:

    method dir-sep(--> Str:D)

Returns the string C<｢\｣> representing canonical directory separator
character.

=for code
IO::Spec::Win32.dir-sep.say; # OUTPUT: «\␤»

=head2 method is-absolute

Defined as:

    method is-absolute(Str:D $path --> Bool:D)

Returns C<True> if the C<$path> starts with a slash (C<"/">) or
backslash (C<"\">), even if they have combining character on them,
optionally preceded by a volume:

    say IO::Spec::Win32.is-absolute: "/foo";        # OUTPUT: «True␤»
    say IO::Spec::Win32.is-absolute: "/\x[308]foo"; # OUTPUT: «True␤»
    say IO::Spec::Win32.is-absolute: ｢C:\foo｣;      # OUTPUT: «True␤»
    say IO::Spec::Win32.is-absolute: "bar";         # OUTPUT: «False␤»

=head2 method join

Defined as:

    method join (Str:D $volume, Str:D $dir, Str:D $file --> Str:D)

Similar to L«C<catpath>|/routine/catpath», takes two path fragments and
concatenates them, adding or removing a path separator, if necessary,
except it will return just C<$file> if both C<$dir> and C<$file> are
string C<'/'> or if C<$dir> is the string C<'.'>. The first argument is
ignored (it exists to maintain consistent interface with other
C<IO::Spec> types for systems that have volumes).

    IO::Spec::Win32.join('C:', '/some/dir', 'foo.txt').say;
    # OUTPUT: «C:/some/dir\and/more␤»

    IO::Spec::Win32.join('C:', '.', 'foo.txt').say;
    # OUTPUT: «C:foo.txt␤»

    IO::Spec::Win32.join('C:', ｢\｣, '/').say;
    # OUTPUT: «C:\␤»

    IO::Spec::Win32.join('//server/share', ｢\｣, '/').say;
    # OUTPUT: «//server/share␤»

    IO::Spec::Win32.join('E:', '', 'foo.txt').say;
    # OUTPUT: «E:foo.txt␤»

=head2 method path

Defined as:

    method path(--> Seq:D)

Splits the value of C«%*ENV<PATH>» (or C«%*ENV<Path>» if the former is not set)
on semicolons (C<";">) and returns a L<Seq|/type/Seq> with each of the resultant
parts, always adding element C<"."> to the head. Removes all double
quotes (C<">) it finds.

    %*ENV<PATH> = 'foo;"bar"/"ber"';
    IO::Spec::Win32.path.raku.say; # OUTPUT: «(".", "foo", "bar/ber").Seq␤»

=head2 method rel2abs

Defined as:

    method rel2abs(Str() $path, $base = $*CWD --> Str:D)

Returns a string representing C<$path> converted to absolute path, based at
C<$base>, which defaults to C<$*CWD>. If C<$base> is not an absolute path,
it will be made absolute relative to C<$*CWD>, unless C<$*CWD> and C<$base>
are the same.

=begin code
say $*CWD;                                   # OUTPUT: «"C:\Users\camelia".IO␤»

say IO::Spec::Win32.rel2abs: 'foo';          # OUTPUT: «C:\Users\camelia\foo␤»
say IO::Spec::Win32.rel2abs: './';           # OUTPUT: «C:\Users\camelia␤»
say IO::Spec::Win32.rel2abs: 'foo/../../';   # OUTPUT: «C:\Users\camelia\foo\..\..␤»
say IO::Spec::Win32.rel2abs: '/foo/';        # OUTPUT: «C:\foo␤»

say IO::Spec::Win32.rel2abs: 'foo', 'bar';   # OUTPUT: «C:\Users\camelia\bar\foo␤»
say IO::Spec::Win32.rel2abs: './', '/bar';   # OUTPUT: «\bar␤»
say IO::Spec::Win32.rel2abs: '/foo/', 'bar'; # OUTPUT: «C:\foo␤»

say IO::Spec::Win32.rel2abs: 'foo/../../', 'bar';
# OUTPUT: «C:\Users\camelia\bar\foo\..\..␤»
=end code

=head2 method rootdir

Defined as:

    method rootdir(--> Str:D)

Returns string C<｢\｣>, representing root directory.

=head2 method split

Defined as:

    method split(IO::Spec::Win32: Cool:D $path)

Creates a L«C<IO::Path::Parts>|/type/IO::Path::Parts» for C<$path>.

=begin code
IO::Spec::Win32.split('C:/foo/bar.txt').raku.say;
# OUTPUT: «IO::Path::Parts.new("C:","/foo","bar.txt")␤»

IO::Spec::Win32.split('/foo/').raku.say;
# OUTPUT: «IO::Path::Parts.new("","/","foo")␤»

IO::Spec::Win32.split('///').raku.say;
# OUTPUT: «IO::Path::Parts.new("","/","\\")␤»

IO::Spec::Win32.split('./').raku.say;
# OUTPUT: «IO::Path::Parts.new("",".",".")␤»

IO::Spec::Win32.split('.').raku.say;
# OUTPUT: «IO::Path::Parts.new("",".",".")␤»

IO::Spec::Win32.split('').raku.say;
# OUTPUT: «IO::Path::Parts.new("","","")␤»
=end code

B<Note>: Before Rakudo version 2020.06 this method split the given
C<$path> into "volume", "dirname", and "basename" and returned the result
as a L<List|/type/List> of three L<Pairs|/type/Pair>, in that order.

=head2 method splitdir

Defined as:

    method splitdir(Cool:D $path --> List:D)

Splits the given C<$path> on slashes and backslashes.

=begin code
IO::Spec::Win32.splitdir('C:\foo/bar.txt').raku.say;
# OUTPUT: «("C:", "foo", "bar.txt")␤»

IO::Spec::Win32.splitdir('/foo/').raku.say;
# OUTPUT: «("", "foo", "")␤»

IO::Spec::Win32.splitdir('///').raku.say;
# OUTPUT: «("", "", "", "")␤»

IO::Spec::Win32.splitdir('./').raku.say;
# OUTPUT: «(".", "")␤»

IO::Spec::Win32.splitdir('.').raku.say;
# OUTPUT: «(".",)␤»

IO::Spec::Win32.splitdir('').raku.say;
# OUTPUT: «("",)␤»
=end code

=head2 method splitpath

Defined as:

    method splitpath(Cool:D $path, :$nofile --> List:D)

Splits the given C<$path> into a list of 3 strings: volume,
dirname, and file. The volume is always an empty string, returned for API
compatibility with other L<IO::Spec|/type/IO::Spec> types. If C<:$nofile> named argument is
set to C<True>, the content of the file string is undefined and should be
ignored; this is a means to get a performance boost, as implementations may use
faster code path when file is not needed.

=begin code
IO::Spec::Win32.splitpath('C:\foo/bar.txt').raku.say;
# OUTPUT: «("C:", "\\foo/", "bar.txt")␤»

IO::Spec::Win32.splitpath('C:\foo/bar.txt', :nofile).raku.say;
# OUTPUT: «("C:", "\\foo/bar.txt", "")␤»

IO::Spec::Win32.splitpath('/foo/').raku.say;
# OUTPUT: «("", "/foo/", "")␤»

IO::Spec::Win32.splitpath('/foo/', :nofile).raku.say;
# OUTPUT: «("", "/foo/", "")␤»

IO::Spec::Win32.splitpath('///').raku.say;
# OUTPUT: «("", "///", "")␤»

IO::Spec::Win32.splitpath('./').raku.say;
# OUTPUT: «("", "./", "")␤»

IO::Spec::Win32.splitpath('.').raku.say;
# OUTPUT: «("", "", ".")␤»

IO::Spec::Win32.splitpath('').raku.say;
# OUTPUT: «("", "", "")␤»
=end code

=head2 method tmpdir

Defined as:

        method tmpdir(--> IO::Path:D)

Attempts to locate a system's temporary directory by checking several typical directories and environmental variables. Uses current directory if no suitable directories are found.

=end pod

# vim: expandtab shiftwidth=4 ft=perl6
